package com.gitee.feizns.dynamic;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.function.IntFunction;
import java.util.stream.Collectors;

/**
 * 对象操作工具类
 * @author feizns
 * @since 2024/12/2
 */
public class Objs {

    /**
     * Determine whether the given object is an array:
     * either an Object array or a primitive array.
     * @param obj the object to check
     */
    public static boolean isArray(Object obj) {
        return (obj != null && obj.getClass().isArray());
    }

    /**
     * Determine whether the given array is empty:
     * i.e. {@code null} or of zero length.
     * @param array the array to check
     * @see #isEmpty(Object)
     */
    public static boolean isEmpty(Object[] array) {
        return (array == null || array.length == 0);
    }

    /**
     * Determine whether the given object is empty.
     * <p>This method supports the following object types.
     * <ul>
     * <li>{@code Optional}: considered empty if not {@link Optional#isPresent()}</li>
     * <li>{@code Array}: considered empty if its length is zero</li>
     * <li>{@link CharSequence}: considered empty if its length is zero</li>
     * <li>{@link Collection}: delegates to {@link Collection#isEmpty()}</li>
     * <li>{@link Map}: delegates to {@link Map#isEmpty()}</li>
     * </ul>
     * <p>If the given object is non-null and not one of the aforementioned
     * supported types, this method returns {@code false}.
     * @param obj the object to check
     * @return {@code true} if the object is {@code null} or <em>empty</em>
     * @since 4.2
     * @see Optional#isPresent()
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }

        if (obj instanceof Optional) {
            return !((Optional<?>) obj).isPresent();
        }
        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length() == 0;
        }
        if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }

        // else
        return false;
    }

    /**
     * 将单元素的集合和数组解析单对象
     * @param obj 对象
     * @return {@link Object}
     */
    public static Object unpack(Object obj) {
        return unwrap(obj);
    }

    /**
     * 将单元素的集合和数组解析单对象
     * @param array 数组
     * @return {@link Object}
     */
    public static Object unwrap(Object array) {
        if ( array != null ) {
            if ( array.getClass().isArray() && Array.getLength(array) == 1 )
                return Array.get(array, 0);
            else if ( array instanceof Optional )
                return ((Optional<?>) array).orElse(null);
            else if ( array instanceof Collection && ((Collection<?>) array).size() == 1 )
                return Lists.first(((Collection<?>) array).iterator());
        }
        return array;
    }

    /**
     * <b>将未知对象装换为数组</b>
     * @param obj 数组
     * @param <T> 数组类型
     * @return 返回指定元素的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(Object obj) {
        return (T[]) toArray(obj, Object[]::new);
    }

    /**
     * <b>将未知的对象封装成功数组</b>
     * @param obj 未知对象
     * @param supplier 数组提供者
     * @param <T> 数组元素类型
     * @return 返回对应的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(Object obj, IntFunction<T[]> supplier) {
        if ( isArray(obj) ) {
            T[] ret = supplier.apply(Array.getLength(obj));
            for (int i = 0; i < Array.getLength(obj); i++)
                ret[i] = (T) Array.get(obj, i);
            return ret;
        } else if ( obj instanceof Collection<?> ) {
            return Lists.toArray((Iterable<T>) obj);
        } else if ( obj instanceof Iterator ) {
            return Lists.toArray((Iterator<T>) obj);
        } else {
            T[] ts = supplier.apply(1);
            ts[0] = (T) obj;
            return ts;
        }
    }

    /**
     * <b>将数组转换成用逗号分隔的字符串</b>
     * <pre>{@code
     *  //例：
     *  System.out.println(toString("A", "B", "C"));//"A,B,C"
     * }</pre>
     * @param array 数组
     * @param <T> 数组类型
     * @return [1,2,3] => "1,2,3"
     */
    @SafeVarargs
    public static <T> String toString(T... array) {
        return toString(",", array);
    }

    /**
     * <b>将数组转换成用逗号分隔的字符串</b>
     * <pre>{@code
     *  //例：
     *  System.out.println(toString("=", "A", "B", "C"));//A=B=C
     * }</pre>
     * @param delimiter 分隔符
     * @param array 数组
     * @param <T> 数组类型
     * @return [1,2,3] if delimiter = "?" => "1?2?3"
     */
    @SafeVarargs
    public static <T> String toString(String delimiter, T... array) {
        return  array != null
                ? java.util.Arrays.stream(array)
                .map(java.util.Objects::toString)
                .collect(Collectors.joining(delimiter))
                : null;
    }

    /**
     * <b>数组强转</b>
     * <pre>{@code
     *  //例：
     *  Object[] array = new String[]{"A", "B", "C"};
     *  String[] stringArray = cast(array, String[]::new);
     *  System.out.println(Arrays.toString(stringArray));//["A", "B", "C"]
     * }</pre>
     * @param array 数组
     * @param generator 数组构建器
     * @param <T> 数组构建器类型（数组目标类型）
     * @return 构建器元素类型的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] cast(Object[] array, IntFunction<T[]> generator) {
        return array != null ? java.util.Arrays.stream(array).map(e -> (T) e).toArray(generator) : null;
    }

}
